/*******************************************************************************
 * Classe Case : Créé des cases qui seront contenues dans le damier et qui
 *               pourront contenir des pions
 ******************************************************************************/
package tp2;

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;

/**
 *
 * @author W&G
 */
public class Case extends JPanel {

    // true si la case est foncée, false sinon
    private boolean estNoire = false;
    // true si le pion qui occupe la case est sélectionné, false sinon
    private boolean pionChoisi = false;
    // true si un pion a déjà été choisi, false sinon
    private static boolean dejaChoisi = false;
    // Couleur actuelle de la case (voir l'enum Couleur)
    private Couleur couleur;
    // lien vers le pion sur la case
    private Pion p;
    // Joueur courant
    private static Jeu.Joueur joueurCourant = Jeu.Joueur.JOUEUR1;
    // La case d'où vient le pion qui se déplace
    private static Case casePrecedente = null;
    // L'état de la case (voir l'enum Etat)
    private Etat etatCourant;
    // Position en x sur le plateau
    private int posX;
    // Position en y sur le plateau
    private int posY;
    // Nombre de pions du joueur 1
    private static int nbPions1 = 0;
    // Nombre de pions du joueur 2
    private static int nbPions2 = 0;
    // true si le SuperRedd du joueur 1 a déjà été joué, false sinon
    private static boolean superReddDejaJoue1 = false;
    // true si le SuperRedd du joueur 2 a déjà été joué, false sinon
    private static boolean superReddDejaJoue2 = false;

    public Case() {
    }

    public enum Couleur {
        // Couleurs de cases

        BLANC1(new Color(150, 255, 230)), BLANC2(new Color(200, 255, 230)),
        NOIR1(new Color(50, 200, 225)), NOIR2(new Color(150, 200, 225)),
        PION1(Color.RED), PION2(Color.GREEN), SUPERREDD1(new Color(190, 30, 30)),
        SUPERREDD2(new Color(0, 170, 0));
        // Couleur actuelle de la case
        private Color couleur;
        // Constructeur des couleurs

        private Couleur(Color c) {
            this.couleur = c;
        }
        // Retourne la couleur actuelle

        public Color getCouleur() {
            return couleur;
        }
    }

    // Différents états possibles pour une case
    public enum Etat {

        VIDE, JOUEUR1, JOUEUR2, SUPERREDD1, SUPERREDD2;
    }

    // Dessine la case et le pion à l'intérieur
    @Override
    public void paintComponent(Graphics g) {
        super.paintComponent(g);

        g.setColor(couleur.getCouleur());
        g.fillRect(0, 0, this.getWidth(), this.getHeight()); // dessine la case
        if (etatCourant != Etat.VIDE) {
            p.paintComponent(g); // seulement s'il y a un pion à dessiner
        }
    }

    /* Constructeur de la case
     * Paramètres:
     * c: si la case est noire
     * x: position horizontale de la case
     * y: position verticale de la case
     */
    public Case(boolean c, int x, int y) {
        super(new BorderLayout());
        if (c) {
            couleur = Couleur.NOIR1;
            estNoire = true;
        } else {
            couleur = Couleur.BLANC1;
        }
        etatCourant = Etat.VIDE;
        this.addMouseListener(new ActionSouris());
        posX = x;
        posY = y;
    }

    // Méthode qui charge les pions selon les données sur l'état de chaque case
    public void chargerPions(Etat etat) {
        this.etatCourant = etat;
        if (p != null) {
            p.setVisible(false);
        }
        pionChoisi = false;
        p = null;
        switch (etat) {
            case JOUEUR1:
            case JOUEUR2:
                p = new Pion(this);
                break;
            case SUPERREDD1:
            case SUPERREDD2:
                p = new SuperRedd(this);
                break;
        }
        repaint();
    }

    // Change les labels au début ou au chargement d'une partie
    public static void chargerLabels() {
        if (joueurCourant == Jeu.Joueur.JOUEUR1) {
            Jeu.getLblTour().setForeground(Couleur.PION1.getCouleur());
            Jeu.getLblTour().setText("Tour : Joueur 1");
        } else {
            Jeu.getLblTour().setForeground(Couleur.PION2.getCouleur());
            Jeu.getLblTour().setText("Tour : Joueur 2");
        }
        calculerNbPions();
    }

    // Retourne un boolean, true si le pion courant est choisi, false sinon
    public boolean getPionChoisi() {
        return pionChoisi;
    }
    // Duplique le pion choisi sur une nouvelle case

    private void dupliquerPion(Jeu.Joueur j, Case deplacement) {
        if (Jeu.getSuperRedd()) {
            p = new SuperRedd(deplacement);
        } else {
            p = new Pion(deplacement);
        }
        this.add(p);
        deselectionnerPion(casePrecedente);
        deplacement.add(p);
    }

    // Déplace un pion sur une nouvelle case
    private void deplacerPion(Jeu.Joueur j, Case deplacement) {
        if (Jeu.getSuperRedd()) {
            p = new SuperRedd(deplacement);
        } else {
            p = new Pion(deplacement);
        }
        this.add(p);
        supprimerPion(casePrecedente);
    }

    // Désélection d'un pion
    private void deselectionnerPion(Case c) {
        c.pionChoisi = false;
        c.repaint();
    }

    // Suppression d'un pion
    private void supprimerPion(Case c) {

        c.p.setVisible(false);
        c.pionChoisi = false;
        c.etatCourant = Etat.VIDE;
        c.p = null;
        c.repaint();
    }

    // Retourne true si le mouvement tenté est un déplacement, false sinon
    private boolean deplacement(Case precedente, Case actuelle) {
        int x, y;
        x = Math.abs(actuelle.posX - precedente.posX);
        y = Math.abs(actuelle.posY - precedente.posY);
        boolean retour = (x <= 2 && y <= 2);
        if (retour) {
            Jeu.getBtnSuperRedd().setEnabled(false);
        }
        return retour;
    }

    // Retourne true si le mouvement tenté est une duplication, false sinon
    private boolean duplication(Case precedente, Case actuelle) {
        int x, y;
        x = Math.abs(actuelle.posX - precedente.posX);
        y = Math.abs(actuelle.posY - precedente.posY);
        boolean retour = (x <= 1 && y <= 1);
        return retour;
    }

    /* Calcule le nombre de pion, change l'affichage du
    nombre de pions et vérifie si un joueur gagne */
    private static void calculerNbPions() {
        nbPions1 = 0;
        nbPions2 = 0;
        for (int i = 0; i < Jeu.getCases().length; i++) {
            for (int j = 0; j < Jeu.getCases()[i].length; j++) {
                if (Jeu.getCases()[i][j].getEtat() == Etat.JOUEUR1
                        || Jeu.getCases()[i][j].getEtat() == Etat.SUPERREDD1) {
                    nbPions1++;
                } else if (Jeu.getCases()[i][j].getEtat() == Etat.JOUEUR2
                        || Jeu.getCases()[i][j].getEtat() == Etat.SUPERREDD2) {
                    nbPions2++;
                }
            }
        }
        switch (nbPions1) {
            case 0:
                Jeu.getLblNbPions1().setText(nbPions1 + " pions");
                Jeu.victoire(Jeu.Joueur.JOUEUR2);
                break;
            case 1:
                Jeu.getLblNbPions1().setText(nbPions1 + " pion");
                break;
            default:
                Jeu.getLblNbPions1().setText(nbPions1 + " pions");
                break;
        }
        switch (nbPions2) {
            case 0:
                Jeu.getLblNbPions2().setText(nbPions2 + " pions");
                Jeu.victoire(Jeu.Joueur.JOUEUR1);
                break;
            case 1:
                Jeu.getLblNbPions2().setText(nbPions2 + " pion");
                break;
            default:
                Jeu.getLblNbPions2().setText(nbPions2 + " pions");
                break;
        }
        if (nbPions1 + nbPions2 == 64) {
            if (nbPions1 > nbPions2) {
                Jeu.victoire(Jeu.Joueur.JOUEUR1);
            } else {
                Jeu.victoire(Jeu.Joueur.JOUEUR2);
            }
        }
    }

    // Change la couleur des pions environnants
    private void changerCouleurs() {
        // Boucles for: vérifient chaque case adjacente
        for (int i = -1; i <= 1; i++) {
            for (int j = -1; j <= 1; j++) {
                // Ne s'occupe pas des cases qui sortiraient du plateau
                if (!(posX + i < 0 || posX + i > 7
                        || posY + j < 0 || posY + j > 7)) {
                    if (Jeu.getCases()[posX + i][posY + j].etatCourant
                            != Etat.VIDE) {
                        if (joueurCourant == Jeu.Joueur.JOUEUR1) {
                            if (Jeu.getSuperRedd()) {
                                if (Jeu.getCases()[posX + i][posY + j].etatCourant != Etat.VIDE) {
                                    supprimerPion(
                                            Jeu.getCases()[posX + i][posY + j]);
                                }
                                Jeu.getCases()[posX + i][posY + j].etatCourant =
                                        Etat.SUPERREDD1;
                                Jeu.getCases()[posX + i][posY + j].p = new SuperRedd(Jeu.getCases()[posX + i][posY + j]);
                                this.add(p);
                            } else {
                                if (Jeu.getCases()[posX + i][posY + j].etatCourant == Etat.JOUEUR2) {
                                    Jeu.getCases()[posX + i][posY + j].etatCourant = Etat.JOUEUR1;
                                }
                                Jeu.getCases()[posX + i][posY + j].repaint();
                            }
                        }
                        if (joueurCourant == Jeu.Joueur.JOUEUR2) {
                            if (Jeu.getSuperRedd()) {
                                supprimerPion(
                                        Jeu.getCases()[posX + i][posY + j]);
                                Jeu.getCases()[posX + i][posY + j].etatCourant =
                                        Etat.SUPERREDD2;
                                Jeu.getCases()[posX + i][posY + j].p = new SuperRedd(Jeu.getCases()[posX + i][posY + j]);
                                this.add(p);
                            } else {
                                if (Jeu.getCases()[posX + i][posY + j].etatCourant == Etat.JOUEUR1) {
                                    Jeu.getCases()[posX + i][posY + j].etatCourant = Etat.JOUEUR2;
                                }
                                Jeu.getCases()[posX + i][posY + j].repaint();
                            }
                        }
                    }
                }
            }
        }
        if (Jeu.getSuperRedd()) {
            if (joueurCourant == Jeu.Joueur.JOUEUR1) {
                superReddDejaJoue1 = true;
            } else {
                superReddDejaJoue2 = true;
            }
        }
    }

    // Méthodes set pour quelques variables
    public static void setSuperReddDejaJoue1(boolean s) {
        superReddDejaJoue1 = s;
    }

    public static void setSuperReddDejaJoue2(boolean s) {
        superReddDejaJoue2 = s;
    }

    public static void setJoueurCourant(Jeu.Joueur joueur) {
        joueurCourant = joueur;
    }

    // Méthodes get pour quelques variables
    // Retourne le nombre de pions du joueur 1
    public static int getNbPions1() {
        return nbPions1;
    }

    // Retourne le nombre de pions du joueur 2
    public static int getNbPions2() {
        return nbPions2;
    }

    //Retourne la case courante
    public Case getCase() {
        return this;
    }

    // Retourne l'état de la case courante
    public Etat getEtat() {
        return etatCourant;
    }

    // Retourne si un pion a déjà été choisi
    public static boolean getDejaChoisi() {
        return dejaChoisi;
    }

    // Retourne le joueur qui doit jouer
    public static Jeu.Joueur getJoueurCourant() {
        return joueurCourant;
    }

    // Retourne si le joueur 1 a déjà joué son SuperRedd
    public static boolean getSuperReddDejaJoue1() {
        return superReddDejaJoue1;
    }

    // Retourne si le joueur 2 a déjà joué son SuperRedd
    public static boolean getSuperReddDejaJoue2() {
        return superReddDejaJoue2;
    }

    // Classe interne gérant les actions
    private class ActionSouris extends MouseAdapter {

        // pâlit la case
        @Override
        public void mouseEntered(MouseEvent me) {
            if (estNoire) {
                couleur = Couleur.NOIR2;
            } else {
                couleur = Couleur.BLANC2;
            }
            repaint();
        }

        // foncit la case
        @Override
        public void mouseExited(MouseEvent me) {
            if (estNoire) {
                couleur = Couleur.NOIR1;
            } else {
                couleur = Couleur.BLANC1;
            }
            repaint();
        }

        @Override
        /* sélectionne un pion s'il pion il y a, désélectionne un pion,
        appelle la méthode de déplacement s'il y a lieu */
        public void mousePressed(MouseEvent me) {
            if (dejaChoisi) {
                if (pionChoisi) {
                    pionChoisi = false;
                    dejaChoisi = false;
                    Jeu.getBtnSuperRedd().setEnabled(false);
                    Jeu.setSuperRedd(false);
                } else {
                    if (etatCourant == Etat.VIDE) {
                        // si la case est à 2 et moins de distance
                        if (deplacement(casePrecedente, getCase())) {
                            // si la case est à 1 de distance
                            if (duplication(casePrecedente, getCase())) {
                                dupliquerPion(joueurCourant, getCase());
                            } else {
                                deplacerPion(joueurCourant, getCase());
                            }
                            changerCouleurs();
                            dejaChoisi = false;

                            /* Changement de joueur et d'état de la case et
                             * remise de Jeu.superRedd à false */
                            if (joueurCourant.equals(Jeu.Joueur.JOUEUR1)) {
                                joueurCourant = Jeu.Joueur.JOUEUR2;
                                if (Jeu.getSuperRedd()) {
                                    etatCourant = Etat.SUPERREDD1;
                                } else {
                                    etatCourant = Etat.JOUEUR1;
                                }
                            } else {

                                joueurCourant = Jeu.Joueur.JOUEUR1;
                                if (Jeu.getSuperRedd()) {
                                    etatCourant = Etat.SUPERREDD2;
                                } else {
                                    etatCourant = Etat.JOUEUR2;
                                }
                            }
                            if (joueurCourant == Jeu.Joueur.JOUEUR1) {
                                Jeu.getLblTour().setForeground(Couleur.PION1.getCouleur());
                                Jeu.getLblTour().setText("Tour : Joueur 1");
                            } else {
                                Jeu.getLblTour().setForeground(Couleur.PION2.getCouleur());
                                Jeu.getLblTour().setText("Tour : Joueur 2");
                            }
                        }
                        Jeu.setSuperRedd(false);
                        calculerNbPions();
                        Jeu.setSauvegarde(false);

                    }
                }
            } else {
                // sélectionne un pion
                if (!(etatCourant == Etat.VIDE)) {
                    if ((etatCourant == Etat.JOUEUR1
                            || etatCourant == Etat.SUPERREDD1)
                            && joueurCourant == Jeu.Joueur.JOUEUR1
                            || (etatCourant == Etat.JOUEUR2
                            || etatCourant == Etat.SUPERREDD2)
                            && joueurCourant == Jeu.Joueur.JOUEUR2) {
                        pionChoisi = true;
                        dejaChoisi = true;
                        casePrecedente = (Case) me.getSource();
                        if (joueurCourant == Jeu.Joueur.JOUEUR1) {
                            if (!superReddDejaJoue1) {
                                Jeu.getBtnSuperRedd().setEnabled(true);
                            }
                        } else {
                            if (!superReddDejaJoue2) {
                                Jeu.getBtnSuperRedd().setEnabled(true);
                            }
                        }
                    }
                }
            }
            repaint();
        }
    }
}
